#include "preHeader.h"
#include "InstanceService.h"
#include "MapServer.h"

InstanceService::InstanceService()
{
}

InstanceService::~InstanceService()
{
	Packet packet;
	while (m_PacketStorage.Dequeue(packet)) {
		SAFE_DELETE(packet.pck);
	}
}

InstanceService::Packet InstanceService::NewInstancePacket(size_t gsIdx, INetPacket* pck)
{
	Packet packet;
	packet.type = Packet::Instance;
	packet.gsIdx = gsIdx;
	packet.pck = pck;
	return packet;
}

InstanceService::Packet InstanceService::NewPlayerPacket(ObjGUID guid, INetPacket* pck)
{
	Packet packet;
	packet.type = Packet::Player;
	packet.guid = guid;
	packet.pck = pck;
	return packet;
}

void InstanceService::PushRecvPacket(const Packet& packet)
{
	m_PacketStorage.Enqueue(packet);
}

void InstanceService::UpdateAllPackets()
{
    uint32 opcode = OPCODE_NONE;
	Packet packet;
    TRY_BEGIN {

		while (m_PacketStorage.Dequeue(packet)) {
			opcode = packet.pck->GetOpcode();
			switch (HandleOneRecvPacket(packet)) {
			case SessionHandleCapture:
				break;
			default:
				SAFE_DELETE(packet.pck);
				break;
			}
		}

	} TRY_END
	CATCH_BEGIN(const IException &e) {
		WLOG("Handle packet opcode[%u] exception occurred.", opcode);
		e.Print();
	} CATCH_END
	CATCH_BEGIN(...) {
		WLOG("Handle packet opcode[%u] unknown exception occurred.", opcode);
	} CATCH_END
}

int InstanceService::HandleOneRecvPacket(const Packet& packet)
{
	switch (packet.type) {
	case Packet::Instance:
		return HandleOneRecvInstancePacket(packet);
	case Packet::Player:
		return HandleOneRecvPlayerPacket(packet);
	default:
		assert(false && "can't reach here.");
		return SessionHandleUnhandle;
	}
}

int InstanceService::HandleOneRecvInstancePacket(const Packet& packet)
{
	auto opcode = packet.pck->GetOpcode();
	auto retCode = HandleInstancePacket(packet);
	switch (retCode) {
	case SessionHandleSuccess:
		break;
	case SessionHandleCapture:
		break;
	case SessionHandleUnhandle:
		WLOG("SessionHandleUnhandle gsIdx(%u) Opcode[%u].", packet.gsIdx, opcode);
		break;
	case SessionHandleWarning:
		WLOG("Handle gsIdx(%u) Opcode[%u] Warning!", packet.gsIdx, opcode);
		break;
	case SessionHandleError:
		WLOG("Handle gsIdx(%u) Opcode[%u] Error!", packet.gsIdx, opcode);
		break;
	case SessionHandleKill:
	default:
		WLOG("Fatal error occurred when processing gsIdx(%u) opcode[%u].", packet.gsIdx, opcode);
		break;
	}
	return retCode != SessionHandleCapture ? SessionHandleSuccess : SessionHandleCapture;
}

int InstanceService::HandleOneRecvPlayerPacket(const Packet& packet)
{
	auto opcode = packet.pck->GetOpcode();
	TRY_BEGIN {

		auto retCode = HandlePlayerPacket(packet);
		switch (retCode) {
		case SessionHandleSuccess:
			break;
		case SessionHandleCapture:
			break;
		case SessionHandleUnhandle:
			WLOG("SessionHandleUnhandle Player(%hu,%u) Opcode[%u].",
				packet.guid.SID, packet.guid.UID, opcode);
			break;
		case SessionHandleWarning:
			WLOG("Handle Player(%hu,%u) Opcode[%u] Warning!",
				packet.guid.SID, packet.guid.UID, opcode);
			break;
		case SessionHandleError:
			WLOG("Handle Player(%hu,%u) Opcode[%u] Error!",
				packet.guid.SID, packet.guid.UID, opcode);
			break;
		case SessionHandleKill:
		default:
			WLOG("Fatal error occurred when processing player(%hu,%u) opcode[%u], "
				"the player has been removed.", packet.guid.SID, packet.guid.UID, opcode);
			sMapServer.KickPlayer(packet.guid, SessionKickNetPacketError);
			break;
		}
		return retCode != SessionHandleCapture ? SessionHandleSuccess : SessionHandleCapture;

	} TRY_END
	CATCH_BEGIN(const IException &e) {
		WLOG("Handle packet player(%hu,%u) opcode[%u] exception occurred.",
			packet.guid.SID, packet.guid.UID, opcode);
		e.Print();
		sMapServer.KickPlayer(packet.guid, SessionKickNetPacketError);
	} CATCH_END
	CATCH_BEGIN(...) {
		WLOG("Handle packet player(%hu,%u) opcode[%u] unknown exception occurred.",
			packet.guid.SID, packet.guid.UID, opcode);
		sMapServer.KickPlayer(packet.guid, SessionKickNetPacketError);
	} CATCH_END

	return SessionHandleSuccess;
}

void InstanceService::AddEventSafe(std::function<void()>&& e)
{
	m_SafeEventStorage.Enqueue(std::move(e));
}

void InstanceService::AddEvent(std::function<void()>&& e)
{
	m_NativeEventStorage.push(std::move(e));
}

void InstanceService::AddEvent(LuaRef&& e)
{
	m_ScriptEventStorage.push(std::move(e));
}

void InstanceService::UpdateAllSafeEvents()
{
	std::function<void()> Event;
	while (m_SafeEventStorage.Dequeue(Event)) {
		Event();
	}
}

void InstanceService::UpdateAllFrameEvents()
{
	for (; !m_NativeEventStorage.empty(); m_NativeEventStorage.pop()) {
		m_NativeEventStorage.front()();
	}
	for (; !m_ScriptEventStorage.empty(); m_ScriptEventStorage.pop()) {
		m_ScriptEventStorage.front().Get<LuaFunc>().Call<void>();
	}
}
